package com.neborosoft.lib.threading;

import java.util.concurrent.Executor;

/**
 * Created with IntelliJ IDEA.
 * User: CM
 * Date: 07.02.13
 * Time: 22:10
 * To change this template use File | Settings | File Templates.
 */
public abstract class AbstractAsyncTask<Args,Result> {
    private OnHostThreadExecutor onHostThreadExecutor;
    private Args queuedTaskArgs;
    private Executor queuedTaskExecutor;
    private volatile boolean cancelled = false;
    private volatile boolean isRunning = false;

    protected AbstractAsyncTask(OnHostThreadExecutor onHostThreadExecutor) {
        if (onHostThreadExecutor == null) {
           throw new NullPointerException();
        }

        this.onHostThreadExecutor = onHostThreadExecutor;
    }

    protected abstract Result doInBackground(Args args);

    protected void onPostExecute(Result result){

    }

    public boolean isCancelled() {
        return cancelled;
    }

    public void cancel() {
        synchronized (this) {
            cancelled = true;
        }
    }

    public void execute(Executor executor){
        execute(null, executor);
    }

    private void executeQueuedTask(){
        synchronized (this) {
            cancelled = false;
            isRunning = false;
            if(queuedTaskExecutor != null){
                execute(queuedTaskArgs, queuedTaskExecutor);
                queuedTaskExecutor = null;
                queuedTaskArgs = null;
            }
        }
    }

    public void execute(final Args args, final Executor executor){
        if(isRunning){
            queuedTaskArgs = args;
            queuedTaskExecutor = executor;
            return;
        }

        isRunning = true;
        executor.execute(new Runnable() {
            @Override
            public void run() {
                final Result result = doInBackground(args);
                if(!isCancelled()){
                    onHostThreadExecutor.runOnHostThread(new Runnable() {
                        @Override
                        public void run() {
                            onPostExecute(result);
                        }
                    });
                }

                executeQueuedTask();
            }
        });
    }
}
